#include "databasemanager.h"

#include <QtCore>
#include <QMetaObject>

Q_GLOBAL_STATIC(DatabaseManager, databaseManager)

DatabaseManager *DatabaseManager::instance()
{
    return databaseManager();
}

DatabaseManager::DatabaseManager(QObject *parent) :
    QThread(parent)
{
    qDebug() << this << ": New databasemanager";

    qRegisterMetaType<ServerInformationList>("ServerInformationList");

    database = QSqlDatabase::addDatabase("QSQLITE");
    database.setHostName("localhost");
    database.setDatabaseName("./bluespheredb");
    bool ok = database.open();
    if(!ok)
        qDebug() << this << ": Failed to open the database:" << database.lastError().text();
    else
        qDebug() << this << ": Database open";

    quit = false;
    state = Idle;
    dbExists = true;
    wokeUp = false;
}

DatabaseManager::~DatabaseManager()
{
    qDebug() << this << ": Delete databasemanager";
    quit = true;
    cond.wakeOne();
    wait();
}

void DatabaseManager::run()
{
    qDebug() << this << ": Starting databasemanager thread";
    do {
        // Go to sleep if there's nothing to do.
        QMutexLocker locker(&mutex);
        if (!quit && state == Idle) {
            qDebug() << this << ": Idle";
            cond.wait(&mutex);
        }

        //mutex.lock();

        if (state == DatabaseExists) {
            qDebug() << this << ": Checking if the database exists";
            dbExists = false;
            QSqlQuery query("SELECT version FROM generalsettings");
            while (query.next()) {
                QString version = query.value(0).toString();
                qDebug() << this << ": query returned:" << version;
                if (version == "1")
                    dbExists = true;
                else
                    dbExists = false;
            }
            emit databaseExists(dbExists);
            state = Idle;
        }

        if (state == CreateDatabase) {
            qDebug() << this << ": Creating a new database";
            QSqlQuery queryCreateTableGeneralSettings("CREATE TABLE generalsettings ( version varchar(3) )");
            QSqlQuery queryInsertSettings("INSERT INTO generalsettings VALUES ('1')");
            QSqlQuery queryCreateTableServers("CREATE TABLE servers ( adres varchar(255), port int, name varchar(255), username varchar(255), password varchar(255) )");
            state = Idle;
        }

        if (state == GetServerList) {
            qDebug() << this << ": Getting the server list";
            ServerInformationList servers;
            servers.clear();
            QSqlQuery query("SELECT * FROM servers");
            while (query.next()) {
                ServerInformation *info = new ServerInformation;
                info->adres = query.value(0).toString();
                info->port = query.value(1).toInt();
                info->name = query.value(2).toString();
                info->username = query.value(3).toString();
                info->password = query.value(4).toString();
                servers << info;
            }
            emit serverList(servers);
            state = Idle;
        }

        if (state == AddServer) {
            if (!temporaryServerInformation) {
                qDebug() << this << ": No server information to add!";
                state = Idle;
                return;
            }
            qDebug() << this << ": Adding a server to the database";
            QString queryString;
            queryString = "";
            queryString = queryString + "INSERT INTO servers Values (";
            queryString = queryString + "'" + temporaryServerInformation->adres + "',";
            queryString = queryString + QString::number(temporaryServerInformation->port) + ",";
            queryString = queryString + "'" + temporaryServerInformation->name + "',";
            queryString = queryString + "'" + temporaryServerInformation->username + "',";
            queryString = queryString + "'" + temporaryServerInformation->password + "')";
            QSqlQuery query;
            if (!query.exec(queryString)) {
                qDebug() << this << ": Query = " << queryString;
                qDebug() << this << ": Error adding a server to the database (" << query.lastError().text() << ")";
            }
            delete temporaryServerInformation;
            emit serverListChanged();
            state = Idle;
        }

        if (state == RemoveServer) {
            if (!temporaryServerInformation) {
                qDebug() << this << ": No server information to remove!";
                state = Idle;
                return;
            }
            qDebug() << this << ": Removing a server to the database";
            QString queryString;
            queryString = "";
            queryString = queryString + "DELETE FROM servers WHERE ";
            queryString = queryString + "adres='" + temporaryServerInformation->adres + "' AND ";
            queryString = queryString + "port=" + QString::number(temporaryServerInformation->port) + " AND ";
            queryString = queryString + "name='" + temporaryServerInformation->name + "' AND ";
            queryString = queryString + "username='" + temporaryServerInformation->username + "' AND ";
            queryString = queryString + "password='" + temporaryServerInformation->password + "'";
            QSqlQuery query;
            if (!query.exec(queryString)) {
                qDebug() << this << ": Query = " << queryString;
                qDebug() << this << ": Error removing a server from the database (" << query.lastError().text() << ")";
            }
            delete temporaryServerInformation;
            emit serverListChanged();
            state = Idle;
        }
        //mutex.unlock();

    } while (!quit);

    qDebug() << this << ": Exiting databasemanager thread";
}

void DatabaseManager::checkDatabaseExists()
{
    QMutexLocker locker(&mutex);
    state = DatabaseExists;

    if (!wokeUp) {
        wokeUp = true;
        QMetaObject::invokeMethod(this, "wakeUp", Qt::QueuedConnection);
    }
}

void DatabaseManager::createDatabase()
{
    QMutexLocker locker(&mutex);
    state = CreateDatabase;

    if (!wokeUp) {
        wokeUp = true;
        QMetaObject::invokeMethod(this, "wakeUp", Qt::QueuedConnection);
    }
}

void DatabaseManager::getServerList()
{
    QMutexLocker locker(&mutex);
    state = GetServerList;

    if (!wokeUp) {
        wokeUp = true;
        QMetaObject::invokeMethod(this, "wakeUp", Qt::QueuedConnection);
    }
}

void DatabaseManager::addServer(ServerInformation *serverInformation)
{
    QMutexLocker locker(&mutex);
    state = AddServer;

    temporaryServerInformation = serverInformation;

    if (!wokeUp) {
        wokeUp = true;
        QMetaObject::invokeMethod(this, "wakeUp", Qt::QueuedConnection);
    }
}

void DatabaseManager::removeServer(ServerInformation *serverInformation)
{
    QMutexLocker locker(&mutex);
    state = RemoveServer;

    temporaryServerInformation = serverInformation;

    if (!wokeUp) {
        wokeUp = true;
        QMetaObject::invokeMethod(this, "wakeUp", Qt::QueuedConnection);
    }
}


void DatabaseManager::wakeUp()
{
    QMutexLocker locker(&mutex);
    wokeUp = false;
    cond.wakeOne();
}
